import { Component, OnInit, ChangeDetectionStrategy, ElementRef, ChangeDetectorRef, AfterViewInit, ViewChild, Renderer2, Inject } from '@angular/core';
import { select, Store } from '@ngrx/store';
import { Overlay, OverlayRef, OverlayKeyboardDispatcher, BlockScrollStrategy, OverlayContainer } from '@angular/cdk/overlay';
import { AppStoreModule } from 'src/app/store';
import { ModalTypes } from 'src/app/store/reducers/member.reducer';
import { getMember, getModalType, getModalVisible } from 'src/app/store/selectors/member.selector';
import { BatchActionsService } from 'src/app/store/batch-actions.service';
import { ESCAPE } from '@angular/cdk/keycodes';
import { DOCUMENT } from '@angular/common';
import { WINDOW } from 'src/app/services/services.module';
import { animate, state, style, transition, trigger } from '@angular/animations';

@Component({
  selector: 'app-wy-layer-modal',
  templateUrl: './wy-layer-modal.component.html',
  styleUrls: ['./wy-layer-modal.component.less'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  animations: [trigger('showHide',[
    state('show', style({ transform:'scale(1)', opacity: 1 })),
    state('hide', style({ transform:'scale(0)', opacity: 0 })),
    transition('show<=>hide', animate('0.1s'))
  ])]
})
export class WyLayerModalComponent implements OnInit,AfterViewInit {
  showModal = 'hide';
  currentModalType: ModalTypes = ModalTypes.Default;
  private visible: boolean = false;
  private overlayRef!: OverlayRef;
  private scrollStrategy!: BlockScrollStrategy;
  private resizeHandler!: () => void;
  private overlayContainerEl!: HTMLElement;

  @ViewChild('modalContainer', { static: false }) private modalRef!: ElementRef;
  constructor(
    @Inject(WINDOW) private win: Window,
    @Inject(DOCUMENT) private doc: Document,
    private store$: Store<AppStoreModule>,
    private overlay: Overlay,
    private elementRef: ElementRef,
    private overlayKeyboardDispatcher: OverlayKeyboardDispatcher,
    private cdr: ChangeDetectorRef,
    private batchActionsServe: BatchActionsService,
    private rd: Renderer2,
    private overlayContainerServe: OverlayContainer,
  ) {
    const appStore$ = this.store$.pipe(select(getMember))
    appStore$.pipe(select(getModalVisible)).subscribe(visible => this.watchModelVisible(visible));
    appStore$.pipe(select(getModalType)).subscribe(type => this.watchModelType(type));
    this.scrollStrategy = this.overlay.scrollStrategies.block();
  }
  ngOnInit(): void {
    this.createOverlay()
  }

  ngAfterViewInit(): void {
    this.overlayContainerEl = this.overlayContainerServe.getContainerElement()
    this.listenResizeToCenter();
  }

  private createOverlay() {
    this.overlayRef = this.overlay.create();
    this.overlayRef.overlayElement.appendChild(this.elementRef.nativeElement);
    this.overlayRef.keydownEvents().subscribe(e => this.keyDownListener(e));
  }

  private keyDownListener(evt: KeyboardEvent){
    if(evt.keyCode === ESCAPE){
      this.hide()
    }
  }

  private watchModelVisible(visible: boolean){
    if(this.visible !== visible){
      this.visible = visible
      this.handleVisibleChange(visible)
    }
  }
  private watchModelType(type: ModalTypes){
    if(this.currentModalType !== type){
      this.currentModalType = type
      this.cdr.markForCheck()
    }
  }
  handleVisibleChange (visible: boolean){
    if(visible){
      this.showModal = 'show'
      this.scrollStrategy.enable();
      this.overlayKeyboardDispatcher.add(this.overlayRef)
      this.listenResizeToCenter();
      this.changePointerEvents("auto")
    }else{
      this.showModal = 'hide'
      this.scrollStrategy.disable();
      this.overlayKeyboardDispatcher.remove(this.overlayRef)
      this.resizeHandler()
      this.changePointerEvents("none")
    }
    this.cdr.markForCheck()
  }

  hide(){
    this.batchActionsServe.controlModal(false)
  }

  private changePointerEvents(type: 'none'|'auto'){
    if(this.overlayContainerEl){
      this.overlayContainerEl.style.pointerEvents = type
    }
  }


  private listenResizeToCenter(){
    const modal = this.modalRef.nativeElement
    const modalSize = this.getHideDomSize(modal);
    this.keepCenter(modal, modalSize)
    this.resizeHandler = this.rd.listen('window', 'resize', () => this.keepCenter(modal, modalSize))
  }

  private keepCenter(modal: HTMLElement, size: { w: number, h: number }){
    const left = (this.getWindowSize().w - size.w) / 2;
    const top = (this.getWindowSize().h - size.h) / 2;

    modal.style.left = left + "px";
    modal.style.top = top + "px";

  }

  private getHideDomSize(dom: HTMLElement){
    return {
      w: dom.offsetWidth,
      h: dom.offsetHeight
    }
  }

  private getWindowSize(){
    return {
      w: this.win.innerWidth || this.doc.documentElement.clientWidth || this.doc.body.offsetWidth,
      h: this.win.innerHeight || this.doc.documentElement.clientHeight || this.doc.body.offsetHeight,
    }
  }
}
